/**
 * 
 */
package vin.echo.core;

import java.io.File;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import vin.echo.core.annotation.Function;
import vin.echo.core.annotation.Service;
import vin.echo.core.configure.EchoConfiguration;
import vin.echo.core.exception.ClassLoopInjectException;
import vin.echo.core.exception.EchoBuildExeception;
import vin.echo.core.exception.ParamenterException;

/**
 * @author Vin.Ma
 *
 */
public class ContextLoader {
	private static final Logger logger=Logger.getLogger(ContextLoader.class);
	
	private ServiceContext serviceContext;
	
	
	public final void loadServices(EchoConfiguration configuration,ServiceContext serviceContext) {
		
		this.serviceContext=serviceContext;
		
		logger.info("begin to load services.");
		try {
			Map<String, File> roots = configuration.getServiceRootPath();
			
			for(Entry<String, File> entry:roots.entrySet()){
				if (entry.getValue().exists() && entry.getValue().isDirectory()) {
					File[] files = entry.getValue().listFiles();
					loadClass(files,entry.getKey());
				}
			}
			
		} catch (ClassNotFoundException e) {
			logger.warn("load service error.");
		} catch (InstantiationException e) {
			logger.warn("load service error. can't create cache for instance.");
		} catch (IllegalAccessException e) {
			logger.warn("load service error. can't create cache for instance.");
		} catch (ParamenterException e) {
			e.printStackTrace();
		} catch (EchoBuildExeception e) {
			e.printStackTrace();
		} catch (ClassLoopInjectException e) {
			e.printStackTrace();
		}
	}

	private void loadClass(File[] files, String packageName)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException, ParamenterException, EchoBuildExeception, ClassLoopInjectException {
		for (File file : files) {
			
			if(file.isDirectory()){
				continue;
			}
			String className = file.getName();
			String fullClassName = packageName + "."
					+ className.split("\\.")[0];

			Class<?> classClass = Class.forName(fullClassName);
			Service aService = classClass.getAnnotation(Service.class);
			if (aService != null) {
				String name = aService.name();
				this.serviceContext.injectService(name, classClass,aService.isPrototype());
				logger.info("inject service:" + name);
				loadMethod(classClass);
			}
		}
	}

	private void loadMethod(Class<?> classClass) {
		Method[] realMethods = classClass.getMethods();
		for (Method m : realMethods) {
			Function function = m.getAnnotation(Function.class);
			if (function != null) {
				String functionName = ContextUtils.genFunctionKey(classClass, function.name());
				this.serviceContext.cacheMethod(functionName, m);

				logger.info("cache method :" + function.name());
			}
		}
	}
}
